#include "Date.h"

#include <cstdlib>

Date::Date(){

}

Date::Date(unsigned short day, unsigned short month, unsigned short year)
{
    setDate(day,month,year);
}

Date::Date(string day, string month, string year)
{
	*this = Data(atoi(day), atoi(month), atoi(year));
}

Date::Date(string date)
{
	vector<string> s = split('/',date);
	*this = Date(s[0],s[1],s[2]);
}

Date::~Date(){

}


unsigned short Date::getYear() const{
    return year;
}

/**
 * Sets the Date's year. Checks if year is not smaller than minYear or bigger than
 * maxYear. If false throws an InvalidYear exception.
 * @param year
 */
void Date::setYear(unsigned short year) {
    setDate(this->day, this->month, year);
}


unsigned short Date::getMonth() const{
    return month;
}

/**
 * Sets the Date's month. Checks if the value is apropriated. If not throws an
 * InvalidMonth exception.
 * @param month
 */
void Date::setMonth(unsigned short month) {
    setDate(this->day, month, this->year);
}


unsigned short Date::getDay() const{
	return day;
}

/**
 * Sets the Date's day. Checks if the value is reasonable. If not throws an 
 * InvalidDay exception.
 * @param day
 */
void Date::setDay(unsigned short day) {
    setDate(day, this->month, this->year);
}

void Date::setDate(unsigned short day, unsigned short month, unsigned short year) {
    if (year < minYear || year > maxYear)
        throw InvalidYear(year);

    if (month > 12 || month < 1)
        throw InvalidMonth(month);

    if (day > 31 || day < 1)
        throw InvalidDay(day);

    if ((month == 4 || month == 6 || month == 9 || month == 11) && (day > 30))
        throw InvalidDay(day);

    if(this->month == 2 && day > 28 && !leapYear(year))
        throw InvalidDay();

    if(day > 29 && this->month == 2 && leapYear(year))
        throw InvalidDay();

    this->year = year;
    this->day = day;
    this->month = month;
}

/**
 * Determines wether 'this' date is the same as the given one.
 * @param date
 * @return true if they are equal, false otherwise.
 */
bool Date::operator== (const Date &date) {
    return ((this->day == date.day) &&
            (this->month == date.month) &&
            (this->year == date.year));
}

/**
 * Determines wether 'this' date is smaller than the given one.
 * @param date
 * @return true if it is smaller, false otherwise
 */
bool Date::operator< (const Date &date) {
    return ((this->day < date.day) &&
            (this->month < date.month) &&
            (this->year < date.year));
}

/**
 * LeapYear (ano Bissexto)
 * @param year
 * @return true if is leap year and false otherwise
 */
bool Date::leapYear(unsigned short year) {
    if( year % 4 == 0)
        return true;

    return false;
}

string Date::printDate(const Date & date){
	stringstream info;

    info << date.day << "/" << date.month << "/"
            << date.year << endl;
    
    return info.str();
}


void Date::newDate(Date &date){
	bool error = true;
	while(error){
		error = false;
		try{
			cout << "\nDate (dd/mm/yyyy): ";
			cin >> temp;
			Date(temp);
		}
		catch(Date::InvalidDay x) {
            x.printError(cerr);
            error = true;
        }
        catch(Date::InvalidMonth x) {
            x.printError(cerr);
            error = true;
        }
        catch(Date::InvalidYear x) {
            x.printError(cerr);
            error = true;
        }
    }
	
}
